package com.itheima.wemedia.service.impl;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.common.constants.BusinessConstants;
import com.itheima.common.exception.LeadNewsException;
import com.itheima.common.util.RequestContextUtil;
import com.itheima.common.vo.PageResultVo;
import com.itheima.wemedia.dto.WmNewsAuthDto;
import com.itheima.wemedia.dto.WmNewsContentNodeDto;
import com.itheima.wemedia.dto.WmNewsDtoSave;
import com.itheima.wemedia.dto.WmNewsPageReqDto;
import com.itheima.wemedia.mapper.WmMaterialMapper;
import com.itheima.wemedia.mapper.WmNewsMaterialMapper;
import com.itheima.wemedia.mapper.WmUserMapper;
import com.itheima.wemedia.pojo.WmMaterial;
import com.itheima.wemedia.pojo.WmNews;
import com.itheima.wemedia.mapper.WmNewsMapper;
import com.itheima.wemedia.pojo.WmNewsMaterial;
import com.itheima.wemedia.pojo.WmUser;
import com.itheima.wemedia.service.WmNewsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.wemedia.vo.WmNewsVo;
import javafx.scene.paint.Material;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @description <p>自媒体图文内容信息 业务实现</p>
 *
 * @version 1.0
 * @package com.itheima.wemedia.service.impl
 */
@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

    @Autowired
    private WmMaterialMapper wmMaterialMapper;

    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;

    @Autowired
    private KafkaTemplate kafkaTemplate;

    @Autowired
    private WmUserMapper wmUserMapper;

    /**
     * 发表文章
     *
     * @param dto
     * @param draft
     */
    @Override
    @Transactional
    public Long submit(WmNewsDtoSave dto, boolean draft) {
        //=================保存数据到文章表wm_news================
        LocalDateTime now = LocalDateTime.now();
        WmNews pojo = new WmNews();
        BeanUtils.copyProperties(dto,pojo);
        pojo.setUserId(RequestContextUtil.getUserId());
        pojo.setCreatedTime(now);
        pojo.setEnable(BusinessConstants.WmNewsConstants.ENABLE_OFF);//下架
        //1. 如果type=-1,则要提取内容中的图片，根据图片的数量来设置type的值
        List<String> contentImages = getImageFromContent(dto);
        if (dto.getType() == BusinessConstants.WmNewsConstants.TYPE_AUTO){// 封面是自动，由内容来提供
            setWmNewsType(pojo, dto, contentImages);
        }
        //2. 根据draft的值，设置status
        if (draft){
            pojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_DRAFT);//草稿
        } else {
            pojo.setSubmitedTime(now);
            pojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_SUBMIT);
        }
        //3. 设置图片内容，多个以逗号分割
        if (!CollectionUtils.isEmpty(dto.getImages())){
            //使用逗号把集合中的每个元素用逗号拼接成字符串
            String imagesString = String.join(",", dto.getImages());
            pojo.setImages(imagesString);
        }
        //4. 保存到文章表wm_news
        if (dto.getId() != null){
            //更新
            updateById(pojo);
            //删除文章与素材的就关系
            removeWmNewsMaterialRelationship(pojo.getId());
        }else {
            pojo.setSubmitedTime(now);
            save(pojo);
        }

        //=================添加文章与素材的关系wm_mews_material================
        saveWmNewsMaterialRelationship(contentImages, pojo);

        // 判断文章的状态，只有是待审核，才发消息给kafka
        if(pojo.getStatus() == BusinessConstants.WmNewsConstants.STATUS_SUBMIT){
            // 自动审核的主题，由后踢管理系统来消费
            kafkaTemplate.send(BusinessConstants.MqConstants.WM_NEWS_AUTO_SCAN_TOPIC, pojo.getId().toString());
        }
        return pojo.getId();
    }

    /**
     * 文章列表分页查询
     *
     * @param dto
     * @return
     */
    @Override
    public PageResultVo pageList(WmNewsPageReqDto dto) {
        //1. 设置分页参数
        IPage<WmNews> pageInfo = new Page<>(dto.getPage(),dto.getSize());
        //2. 查询条件
        LambdaQueryWrapper<WmNews> lqw = new LambdaQueryWrapper<>();
        lqw.eq(null != dto.getChannelId(),WmNews::getChannelId,dto.getChannelId());
        lqw.like(StringUtils.isNotEmpty(dto.getKeyword()),WmNews::getTitle,dto.getKeyword());
        lqw.ge(null != dto.getBeginPubDate(),WmNews::getPublishTime,dto.getBeginPubDate());
        lqw.le(null != dto.getEndPubDate(),WmNews::getPublishTime,dto.getEndPubDate());
        //3. 查询
        page(pageInfo, lqw);
        //4. 构建结果返回
        return PageResultVo.pageResult(dto.getPage(),dto.getSize(),pageInfo.getTotal(),pageInfo.getRecords());
    }

    /**
     * 通过id删除文章
     *
     * @param newsId
     */
    @Override
    @Transactional
    public void deleteById(Long newsId) {
        //1. 通过id 查询文章信息
        WmNews wmNews = getById(newsId);
        //2. 判断状态与是否上架
        if(wmNews.getStatus() == BusinessConstants.WmNewsConstants.STATUS_PUBLISHED ||
                wmNews.getEnable() == BusinessConstants.WmNewsConstants.ENABLE_ON){
            throw new LeadNewsException("文章已发布或已上架，不能删除!");
        }
        //3. 删除文章
        removeById(newsId);
        //4. 删除文章与素材的关系
        removeWmNewsMaterialRelationship(newsId);

    }

    /**
     * 文章上下架
     *
     * @param paramMap
     */
    @Override
    public void downOrUn(Map<String, Integer> paramMap) {
        Integer newsId = paramMap.get("id");
        Integer enable = paramMap.get("enable");
        //1. 通过id查询
        WmNews wmNews = getById(newsId);
        //2. 判断状态是否为已发布
        if(wmNews.getStatus() != BusinessConstants.WmNewsConstants.STATUS_PUBLISHED){
            throw new LeadNewsException("文章未发布，不能上架或下架!");
        }

        //3. 更新文章的enable值
        WmNews updatePojo = new WmNews();
        updatePojo.setEnable(enable);

        if(enable == BusinessConstants.WmNewsConstants.ENABLE_OFF){
            // 下架操作,同步更新状态为1
            updatePojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_SUBMIT);
            updatePojo.setSubmitedTime(LocalDateTime.now());
        }
        updatePojo.setId(wmNews.getId());
        // 通过id更新
        updateById(updatePojo);
    }

    /**
     * 给平台管理系统，查询文章列表，人工审核用的
     *
     * @param dto
     * @return
     */
    @Override
    public PageResultVo pagelist4Admin(WmNewsPageReqDto dto) {
        //1. 设置分页参数
        IPage<WmNews> pageInfo = new Page<>(dto.getPage(),dto.getSize());
        //2. 构建查询条件
        LambdaQueryWrapper<WmNews> lqw = new LambdaQueryWrapper<>();
        lqw.eq(null != dto.getStatus(), WmNews::getStatus,dto.getStatus());
        lqw.like(StringUtils.isNotEmpty(dto.getTitle()), WmNews::getTitle,dto.getTitle());
        //分页查询
        page(pageInfo,lqw);
        List<WmNewsVo> voList = new ArrayList<>();
        //3.1判断是否有结果集
        List<WmNews> wmNewsList = pageInfo.getRecords();
        if (!CollectionUtils.isEmpty(wmNewsList)){
            //3.2 有结果集，提取文章作者id
            List<Long> userIds = wmNewsList.stream().map(WmNews::getUserId).collect(Collectors.toList());
            //3.3 批量查询文件作者信息
            List<WmUser> wmUserList = wmUserMapper.selectBatchIds(userIds);
            //Map<Long,WmUser> userInfoMap = new HashMap<>();
            /*for (WmUser wmUser : wmUserList) {
                userInfoMap.put(wmUser.getId(), wmUser);
            }*/
            Map<Long, WmUser> userInfoMap = wmUserList.stream().collect(Collectors.toMap(WmUser::getId, Function.identity()));

            //3.4 文章信息转成WmNewsVo
            for (WmNews wmNews : wmNewsList) {
                //得到每个文章
                //获取作者id
                Long userId = wmNews.getUserId();
                WmUser user = userInfoMap.get(userId);
                WmNewsVo vo = WmNewsVo.build(wmNews, user.getName());
                voList.add(vo);
            }

        }
        //4. 构建结果返回
        return PageResultVo.pageResult(dto.getPage(),dto.getSize(),pageInfo.getTotal(),voList);
    }

    /**
     * 给平台管理系统，人工审核 通过
     *
     * @param dto
     * @return
     */
    @Override
    public boolean authPass(WmNewsAuthDto dto) {
        Long wmNewsId = dto.getId();
        WmNews wmNews = getById(wmNewsId);
        // 判断状态是否为人工审核
        if (null != wmNews && wmNews.getStatus() == BusinessConstants.WmNewsConstants.STATUS_MANUAL){
            //是人工审核才可以更新
            WmNews updatePojo = new WmNews();
            updatePojo.setId(dto.getId());
            updatePojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_MANUAL_PASS);
            return updateById(updatePojo);
        }
        return false;
    }

    /**
     * 给平台管理系统，人工审核 驳回
     *
     * @param dto
     * @return
     */
    @Override
    public boolean authFail(WmNewsAuthDto dto) {
        Long wmNewsId = dto.getId();
        WmNews wmNews = getById(wmNewsId);
        // 判断状态是否为人工审核
        if (null != wmNews && wmNews.getStatus() == BusinessConstants.WmNewsConstants.STATUS_MANUAL){
            //是人工审核才可以更新
            WmNews updatePojo = new WmNews();
            updatePojo.setId(dto.getId());
            updatePojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_FAIL);
            updatePojo.setReason(dto.getMsg());
            return updateById(updatePojo);
        }
        return false;
    }

    /**
     * 查询文章详情
     *
     * @param wmNewsId
     * @return
     */
    @Override
    public WmNewsVo getOneVo(Long wmNewsId) {
        WmNews wmNews = getById(wmNewsId);
        if (null != wmNews){
            //获取作者
            WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
            return WmNewsVo.build(wmNews,wmUser.getName());
        }
        return null;
    }

    /**
     * 删除文章与素材旧关系
     * @param id 文章id
     */
    private void removeWmNewsMaterialRelationship(Long id) {
        LambdaQueryWrapper<WmNewsMaterial> lqw = new LambdaQueryWrapper<>();
        lqw.eq(WmNewsMaterial::getNewsId, id);
        wmNewsMaterialMapper.delete(lqw);
    }


    /**
     * type为-1时的处理
     * @param pojo
     * @param dto
     * @param contentImages
     */
    private void setWmNewsType(WmNews pojo, WmNewsDtoSave dto, List<String> contentImages) {
        //1. 获取内容图片的数量
        int size = contentImages.size();
        //2. 判断数量 0 3
        if (size == 0){
            //没有图片
            pojo.setType(BusinessConstants.WmNewsConstants.TYPE_NONE_IMG);// 无图
            pojo.setImages("");
            dto.setImages(null);
        } else if (size < 3){
            pojo.setType(BusinessConstants.WmNewsConstants.TYPE_SINGLE_IMG); // 单图
            /*List<String> list = new ArrayList<>();
            list.add(contentImages.get(0));*/
            //取第一个图片
            dto.setImages(contentImages.stream().limit(1).collect(Collectors.toList()));
        } else {
            pojo.setType(BusinessConstants.WmNewsConstants.TYPE_MULTIPLE_IMG);// 多图
            dto.setImages(contentImages.stream().limit(3).collect(Collectors.toList()));
        }
    }

    private void saveWmNewsMaterialRelationship(List<String> contentImages, WmNews pojo) {
        //1. 图片来源2个地方
        //2. 封面处理，前端过来的是全路径，去掉前缀 去除fileId
        String images = pojo.getImages();
        if (!StringUtils.isEmpty(images)){
            // 图片全路径 去掉前缀 去除fileId
            String[] urlArr = images.split(",");
            List<String> list = Arrays.asList(urlArr);
            saveRelationship(pojo, list, BusinessConstants.WmNewsConstants.WM_CONTENT_REFERENCE);//封面图片
        }
        saveRelationship(pojo, contentImages, BusinessConstants.WmNewsConstants.WM_CONTENT_REFERENCE);//内容图片

    }

    private void saveRelationship(WmNews pojo, List<String> list, int type) {
        for (String fullPath : list) {
            String url = removePrefix(fullPath);
            //3. 查询素材表，得到它们id
            long materialId = getMaterialIdByUrl(url);
            //4. 添加到文章与素材关系表 type=1
            WmNewsMaterial wmNewsMaterial = new WmNewsMaterial();
            wmNewsMaterial.setType(type);// 封面
            wmNewsMaterial.setNewsId(pojo.getId());
            wmNewsMaterial.setMaterialId(materialId);
            wmNewsMaterial.setOrd(1);
            wmNewsMaterialMapper.insert(wmNewsMaterial);
        }
    }

    private long getMaterialIdByUrl(String url){
        LambdaQueryWrapper<WmMaterial> lqw = new LambdaQueryWrapper<>();
        lqw.eq(WmMaterial::getUrl, url);
        WmMaterial material = wmMaterialMapper.selectOne(lqw);
        if (null == material){
            //报错
            throw new LeadNewsException("查不到相应的素材");
        }
        return material.getId();
    }

    /**
     * 提取文章内容对象
     * @param dto
     * @return
     */
    private List<String> getImageFromContent(WmNewsDtoSave dto) {
        String content = dto.getContent();
        //转成java对象
        List<WmNewsContentNodeDto> contentNodeList = JSON.parseArray(content, WmNewsContentNodeDto.class);
        // type = image才是图片
        List<String> urlList = contentNodeList.stream().filter(n -> BusinessConstants.WmNewsConstants.CONTENT_IMAGE.equals(n.getType()))
                .map(WmNewsContentNodeDto::getValue).collect(Collectors.toList());
        /*List<String> urlList = new ArrayList<>();
        for (WmNewsContentNodeDto wmNewsContentNodeDto : contentNodeList) {
            if ("image".equals(wmNewsContentNodeDto.getType())){
                String url = wmNewsContentNodeDto.getValue();
                urlList.add(url);
            }
        }*/
        return urlList;
    }

    private String removePrefix(String url){
        return url.replaceAll("http://((\\d){1,3}\\.){3}(\\d){1,3}:?(\\d){0,5}\\/", "");
    }

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");
        System.out.println(String.join(",", list));
    }
}
